//------------------------------------------------------------------------------ 
//      Copyright (c) 2004-2009, Be Nanashi-San 
// 
//      Permission is hereby granted, free of charge, to any person obtaining a 
//      copy of this software and associated documentation files (the "Software"), 
//      to deal in the Software without restriction, including without limitation 
//      the rights to use, copy, modify, merge, publish, distribute, sublicense, 
//      and/or sell copies of the Software, and to permit persons to whom the 
//      Software is furnished to do so, subject to the following conditions: 
// 
//      The above copyright notice and this permission notice shall be included in 
//      all copies or substantial portions of the Software. 
// 
//      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
//      IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//      FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
//      AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
//      LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
//      FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
//      DEALINGS IN THE SOFTWARE. 
// 
//      File Name:   mainWindow.cpp
//      Author:      Be Nanashi-San 
//      Description: 	 
//------------------------------------------------------------------------------
#include <Beep.h>
#include <Debug.h> // for PRINT()
#include <FindDirectory.h>
#include <Menu.h>
#include <MenuBar.h>
#include <MenuItem.h>
#include <Message.h>
#include <Messenger.h>
#include <Path.h>
#include <String.h>
#include <Window.h>
#include <stdio.h>
#include <string.h>
#include <ScrollBar.h>
#include <Alert.h>
#include <ScrollView.h>
#include <LayoutBuilder.h>
#include <SplitView.h>
#include <TabView.h>

#include "config.h"
#include "2chPositive.h"
#include "BoardListView.h"
#include "BoardOutLineListView.h"
#include "BBSHandler.h"
#include "Bookmark2ch.h"
#include "DisplayThreadView.h"
#include "StatusBarView.h"
#include "ThreadListView.h"
#include "Util.h"
#include "mainWindow.h"
#include "messages.h"
#include "setting.h"
#include "K2chTextView.h"
#include "history.h"

////////////////////////////////////////////////////////////////////////////////
// mainWindow
//
//
////////////////////////////////////////////////////////////////////////////////
mainWindow::mainWindow(BRect frame)
				: BWindow(frame, "2chPositive", B_TITLED_WINDOW, 
				  B_QUIT_ON_WINDOW_CLOSE | B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS)
{
	BMenuBar *menubar = new BMenuBar("");
	fStatusBar = new StatusBarView();
	fThreadListView = new ThreadListView();
	fBoardListView = new BoardListView();
	fBoardListView->SetExplicitMinSize(BSize(100,B_SIZE_UNSET));
	fBoardListView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED,B_SIZE_UNLIMITED));

	BLayoutBuilder::Group<>(this, B_VERTICAL)
		.Add(menubar)
		.AddSplit(B_HORIZONTAL, 1.0f)
			.Add(fBoardListView, 0.3f)
			.AddSplit(B_VERTICAL, 1.0f)
					.Add(fThreadListView, 0.5f)
					.Add(fTabView = new BTabView("tab view"), 0.5f)
					.End()
		.End()
		.Add(fStatusBar);
	
	fHistory = new History(5);
	
	this->AddNewTab();
	this->SetupMenu(menubar);
	(fBoardListView->OutLineView())->MakeFocus(true);
}
////////////////////////////////////////////////////////////////////////////////
// AddNewTab
//
// haikuのterminalより
////////////////////////////////////////////////////////////////////////////////
void
mainWindow::AddNewTab()
{
	if (fTabView->CountTabs() == MAXTAB) {
		char s[256];
		sprintf(s,"タブは%d個までです。",MAXTAB);
		(new BAlert("", s, "OK"))->Go();
		return;
	}

//	BRect r = fTabView->Bounds();
//	r.InsetBy(-3,-1);
//	r.bottom -= fTabView->TabHeight();
	fTabView->AddTab(new DisplayThreadView());

	if (fTabView->CountTabs() == 1) {
		fTabView->Select(0);
	}
}
////////////////////////////////////////////////////////////////////////////////
// QuitRequested
//
//
////////////////////////////////////////////////////////////////////////////////
bool
mainWindow::QuitRequested()
{
	(static_cast<a2chViewer *>(be_app)->CurReader())
		->WriteExpanded(fBoardListView->OutLineView());	// 終了する前に保存する

	theSettings().SetRect(kSETTING_WINDOW_RECT,this->Frame());
//	theSettings().SetPoint(kSETTING_H_SPLITTER_POINT,fHSplitPane->GetBarPosition());
//	theSettings().SetPoint(kSETTING_V_SPLITTER_POINT,fVSplitPane->GetBarPosition());
	delete fHistory;

	return true;
}
////////////////////////////////////////////////////////////////////////////////
// DispatchMessage
//
//
////////////////////////////////////////////////////////////////////////////////
void
mainWindow::DispatchMessage(BMessage *msg, BHandler *handler)
{
	if (msg->what == B_SIMPLE_DATA && msg->HasRef("refs")) {
		BMessage message(*msg);
		message.what = B_REFS_RECEIVED;
		be_app_messenger.SendMessage(&message);
	}else{
		BWindow::DispatchMessage(msg, handler);
	}
}
////////////////////////////////////////////////////////////////////////////////
// MessageReceived
//
//
////////////////////////////////////////////////////////////////////////////////
void
mainWindow::MessageReceived(BMessage *msg)
{
	switch (msg->what) {
		case B_SIMPLE_DATA:{
			PRINT(("mainWindow "));
			break;
		}			
		//zeta 2 スレ@713のBe名無しさんより。
		case kMENU_BOOKMARK_ADD:{
			BMessage query('qury');
			if(this->CurrentQuery(&query)){
				fBookmark->AddBookmark(&query);
			}
			break;
		}
		case kMENU_BOOKMARK_SHOW:
			fBookmark->OpenBookmarkFolder();
			break;

		case kMSG_BOOKMARK:
			fBoardListView->OpenBookmark(msg);
			break;

		case B_NODE_MONITOR:
			fBookmark->WatchMessage(msg);
			break;

		case kMSG_FIND:{
			int32 i;
			msg->FindInt32("targetview", &i);
			BHandler *handler[3]={this->ActiveDisplayThreadView(),fThreadListView,fBoardListView->OutLineView()};
			BHandler *h = handler[i];	// 20050702:gcc2 fix
			BMessenger(h).SendMessage(msg);
			}
			break;

		case kMSG_OPEN_THREAD:
			BMessenger(this->ActiveDisplayThreadView()).SendMessage(msg);
			fTabView->DrawTabs();
			break;
		case kMENU_THREAD_REFREASH:
 		case kMSG_JUMP:
 		case kMEG_WRITE_BUTTON: // StatusBarより
			BMessenger(this->ActiveDisplayThreadView()).SendMessage(msg);
			break;
		
		case kMSG_UPDATE_THREADCOUNT:
			BMessenger(fThreadListView).SendMessage(msg);
			break;
		
		case kMENU_FILE_OFFLINE:
		case kMSG_STATUS_MESSAGE:
		//	BMessenger(fStatusBar).SendMessage(msg);
			break;
		
		case kMENU_EDIT_OPENPREFERNCE:
			be_app_messenger.SendMessage(kMENU_EDIT_OPENPREFERNCE);
			break;
		
		case kMENU_FILE_NEWWINDOW:
		case kMENU_HELP:
			be_app_messenger.SendMessage(kNOT_INPLEMENTED);
			break;

		case kUPDATEPREFS:
			this->Broadcast(msg);
			break;

		case kMENU_HISTORY_BACK:
			this->Back();
			break;		
		
		case kMENU_HISTORY_FORWARD:
			this->Forward();
			break;

#if(MAXTAB > 1)
		case kMENU_NEWTAB:
			this->AddNewTab();
			break;
#endif		
		default:
			BWindow::MessageReceived (msg);
			break;
	}
}
////////////////////////////////////////////////////////////////////////////////
// SetupMenu
// メニュー作成。
//
////////////////////////////////////////////////////////////////////////////////
void
mainWindow::SetupMenu(BMenuBar *menubar)
{
K2chTextView* text = this->ActiveDisplayThreadView()->Text();
BMenuItem *item;
	// File メニュー
	BMenu *menu = new BMenu("ファイル");
	menu->AddItem(MakeItem(this, "新規ウインドウ", kMENU_FILE_NEWWINDOW, 'N'));
#if(MAXTAB > 1)
	menu->AddItem(MakeItem(this, "新規タブ", kMENU_NEWTAB, 'T'));
#endif
	menu->AddSeparatorItem();
	menu->AddItem(MakeItem(this, "閉じる", B_QUIT_REQUESTED, 'W'));
	menu->AddSeparatorItem();
	item = MakeItem(this, "オフライン", kMENU_FILE_OFFLINE);
	item->SetMarked(theSettings().GetBool(kSETTING_OFFLINE));
	menu->AddItem(item);
	menu->AddSeparatorItem();
	menu->AddItem(MakeItem(be_app, "2chPositiveについて" B_UTF8_ELLIPSIS, B_ABOUT_REQUESTED));
	menu->AddSeparatorItem();
	menu->AddItem(MakeItem(this, "終了", B_QUIT_REQUESTED, 'Q'));
	menubar->AddItem(menu);
	
	// Edit メニュー	
	menu = new BMenu("編集");
	menu->AddItem(MakeItem(text, "切り取り" , B_CUT, 'X'));
	menu->AddItem(MakeItem(text, "コピー" , B_COPY, 'C'));
	menu->AddItem(MakeItem(text, "貼り付け" , B_PASTE, 'V'));
	menu->AddSeparatorItem();
	menu->AddItem(MakeItem(text, "全てを選択" , B_SELECT_ALL, 'A'));
	menu->AddSeparatorItem();
	menu->AddItem(MakeItem(be_app, "検索" , kMENU_EDIT_FIND, 'F'));
	menu->AddItem(MakeItem(be_app, "次検索" , kMENU_EDIT_FINDAGAIN, 'G'));
	menu->AddSeparatorItem();
	menu->AddItem(MakeItem(this, "設定" B_UTF8_ELLIPSIS, kMENU_EDIT_OPENPREFERNCE));
	fEditMenu = menu;
	menubar->AddItem(menu);

	// BoardListメニュー	
	menu = new BMenu("板一覧");
	menu->AddItem(MakeItem(fBoardListView, "再読込", kMENU_BOARDLIST_REFREASH));
	menu->AddSeparatorItem();
	menu->AddItem(MakeItem(fBoardListView, "全てを展開", kMENU_BOARDLIST_EXPANDALL, '+'));
	menu->AddItem(MakeItem(fBoardListView, "全てを省略", kMENU_BOARDLIST_COLLAPSEALL, '-'));
	menubar->AddItem(menu);
	fBoardMenu = menu;
	
	// ThreadListメニュー	
	menu = new BMenu("スレ一覧");
	menu->AddItem(MakeItem(fThreadListView, "再読込", kMENU_THREADLIST_REFREASH, 'R', B_COMMAND_KEY | B_SHIFT_KEY));
	fThreadMenu = menu;
	menubar->AddItem(menu);
	
	// Threadメニュー	
	menu = new BMenu("スレ");
	menu->AddItem(MakeItem(this->ActiveDisplayThreadView(), "再読込", kMENU_THREAD_REFREASH, 'R'));
	menu->AddSeparatorItem();
	menu->AddItem(MakeItem(this, "書き込み", kMEG_WRITE_BUTTON));
	menu->AddItem(MakeItem(be_app, "スレ立て", kNOT_INPLEMENTED));
	menu->AddSeparatorItem();
	menu->AddItem(MakeItem(be_app, "ジャンプ", kMENU_THREAD_JUMP, ','));
	menu->AddItem(MakeItem(this->ActiveDisplayThreadView(), "webブラウザで開く", kMENU_THREAD_OPEN_WEBBROWER));
	menu->AddSeparatorItem();
	// 20060806
	// すれ数を設定より変更。
	BString	threadMenuName;
	this->DispRange(threadMenuName, "1から" );
	menu->AddItem(MakeItem(text, threadMenuName.String(), kMENU_THREAD_GO_TOP, 'S', B_COMMAND_KEY | B_SHIFT_KEY));
	this->DispRange(threadMenuName, "最新" );
	menu->AddItem(MakeItem(text, threadMenuName.String(), kMENU_THREAD_GO_LAST, 'E', B_COMMAND_KEY | B_SHIFT_KEY));
	this->DispRange(threadMenuName, "前" );
	menu->AddItem(MakeItem(text, threadMenuName.String(), kMENU_THREAD_GO_PREV, 'P', B_COMMAND_KEY | B_SHIFT_KEY));
	this->DispRange(threadMenuName, "次" );
	menu->AddItem(MakeItem(text, threadMenuName.String(), kMENU_THREAD_GO_NEXT, 'N', B_COMMAND_KEY | B_SHIFT_KEY));
	fThreadMenu = menu;
	menubar->AddItem(menu);
	
	// History メニュー	
	menu = new BMenu("履歴");
	menu->AddItem(MakeItem(this, "戻る", kMENU_HISTORY_BACK, B_LEFT_ARROW, B_COMMAND_KEY | B_SHIFT_KEY));
	menu->AddItem(MakeItem(this, "進む", kMENU_HISTORY_FORWARD, B_RIGHT_ARROW, B_COMMAND_KEY | B_SHIFT_KEY));
	menu->AddSeparatorItem();
	fBistoryMenu = menu;
	menubar->AddItem(menu);

	// Bookmarks メニュー	
	menu = new BMenu("お気に入り");
	menu->AddItem(MakeItem(this, "お気に入りに追加", kMENU_BOOKMARK_ADD));
	menu->AddItem(MakeItem(this, "お気に入りを表示", kMENU_BOOKMARK_SHOW));
	menu->AddSeparatorItem();
	fBookmarkMenu = menu;
	fBookmark = new Bookmark2ch(menu, BMessenger(this));
	menubar->AddItem(menu);

	// Helpメニュー	
	menu = new BMenu("ヘルプ");
	menu->AddItem(MakeItem(this, "ヘルプ", kMENU_HELP));
	menubar->AddItem(menu);
}
////////////////////////////////////////////////////////////////////////////////
// MenusBeginning
// CurrentFocusによってAddBookmarkが可能か調べる
// zeta 2 スレ@757のBe名無しさんより。
////////////////////////////////////////////////////////////////////////////////
void
mainWindow::MenusBeginning()
{
	BView *cView = CurrentFocus();
// Edit
	bool b = (cView ==  this->ActiveDisplayThreadView()->FindView("2ch:TextView")); 
	(fEditMenu->ItemAt(0))->SetEnabled(b);
	(fEditMenu->ItemAt(1))->SetEnabled(b);
	(fEditMenu->ItemAt(2))->SetEnabled(b);
	(fEditMenu->ItemAt(4))->SetEnabled(b);

// Thread List

//20060806
// Thread
	BString	threadMenuName;
	this->DispRange(threadMenuName, "1から" );
	(fThreadMenu->ItemAt(8))->SetLabel(threadMenuName.String());
	this->DispRange(threadMenuName, "最新" );
	(fThreadMenu->ItemAt(9))->SetLabel(threadMenuName.String());
	this->DispRange(threadMenuName, "前" );
	(fThreadMenu->ItemAt(10))->SetLabel(threadMenuName.String());
	this->DispRange(threadMenuName, "次" );
	(fThreadMenu->ItemAt(11))->SetLabel(threadMenuName.String());

//history
	(fBistoryMenu->ItemAt(0))->SetEnabled(fHistory->CanBack());
	(fBistoryMenu->ItemAt(1))->SetEnabled(fHistory->CanForward());
	this->DeleteHistoryMenu();
	this->DispHistory();

// bookmark
//20050626:CurrentQueryの値を使うように修正。
	(fBookmarkMenu->ItemAt(0))->SetEnabled(this->CurrentQuery(NULL));
}
////////////////////////////////////////////////////////////////////////////////
// DispRange
//
//
////////////////////////////////////////////////////////////////////////////////
// TODO(Refactoring): 各viewの親クラスに入らないか？
void
mainWindow::DispRange(BString &s, const char *msg)
{
	int32 displayRange = atoi(theSettings().GetString(DISPLAY_THREAD_RANGE));
	s = "";
	s << msg << displayRange << "レス表示。";
}

////////////////////////////////////////////////////////////////////////////////
// CurrentQuery
// CurrentFocusによってCurrentQueryを切り分ける
// zeta 2 スレ@757のBe名無しさんより。
////////////////////////////////////////////////////////////////////////////////
// TODO(Refactoring): 各viewの親クラスに入らないか？
bool
mainWindow::CurrentQuery(BMessage *query)
{
	BView *cView = CurrentFocus();
	if (!cView) return false;
	
	if (cView == fBoardListView->OutLineView()){
		return (fBoardListView->OutLineView())->CurrentQuery(query);
	}
	
	if (cView == fThreadListView) {
		return fThreadListView->CurrentQuery(query);
	}
	return false;
}

////////////////////////////////////////////////////////////////////////////////
// Broadcast
// 	設定の変更を処理する必要があるが何処で処理されるか解らない。
//	そこで該当するBViewへとりあえず送ってみる
// BeOS - Zeta R5 Be名無し 462さんより、ループするとのこと。
//	PostMessageした先のBViewで受け取らないとBWindowへ戻ってくるようだ。そしてまた送っていた。
////////////////////////////////////////////////////////////////////////////////
void
mainWindow::Broadcast(BMessage *msg)
{
	PostMessage(msg, fBoardListView);
	PostMessage(msg, fThreadListView);
	PostMessage(msg, this->ActiveDisplayThreadView());
}
////////////////////////////////////////////////////////////////////////////////
//
//
//
////////////////////////////////////////////////////////////////////////////////
void
mainWindow::DeleteHistoryMenu()
{
	while(BMenuItem *i = fBistoryMenu->RemoveItem(3)){
		delete i;
	}
}
////////////////////////////////////////////////////////////////////////////////
//
//
//
////////////////////////////////////////////////////////////////////////////////
void
mainWindow::DispHistory()
{
	for(int32 i = fHistory->Size() - 1; i >= 0 ; i--){
		BMessage *m = fHistory->At(i);
		BString title;
		m->FindString("title", &title);
		BMessage *mm = new BMessage(*m);
		
		fBistoryMenu->AddItem(new BMenuItem(title.String(), mm));
	}
}
////////////////////////////////////////////////////////////////////////////////
//
//
//
////////////////////////////////////////////////////////////////////////////////
void
mainWindow::AddHistory(BMessage &m)
{
	fHistory->Add(m);
}
////////////////////////////////////////////////////////////////////////////////
//
//
//
////////////////////////////////////////////////////////////////////////////////
void
mainWindow::Back()
{
	BMessage *m = fHistory->Back();
	if (m)	BMessenger(this->ActiveDisplayThreadView()).SendMessage(m);
}
////////////////////////////////////////////////////////////////////////////////
//
//
//
////////////////////////////////////////////////////////////////////////////////
void
mainWindow::Forward()
{
	BMessage *m = fHistory->Forward();
	if (m)	BMessenger(this->ActiveDisplayThreadView()).SendMessage(m);
}
////////////////////////////////////////////////////////////////////////////////
//
//
// haikuのterminalより
////////////////////////////////////////////////////////////////////////////////
DisplayThreadView *
mainWindow::ActiveDisplayThreadView()
{
	return (DisplayThreadView *)(fTabView->ViewForTab(fTabView->Selection()));
}

